from PyQt5.QtWidgets import *
from PyQt5.QtWidgets import QPushButton
from pyqtgraph import QtCore, QtGui
from PyQt5 import QtWidgets
from threading import Thread
import os
import configparser
import globalType
import globalvar
import multiprocessing
import importlib
import module_strategyprocess
import numba as nb

global dict_strategy, dict_strategyrun, dict_strategyperiod, dict_strategyopenrule, dict_strategycloserule
# 策略文件名称
dict_strategy = {}
# 保存策略开启状态
dict_strategyrun = {}
# 保存策略周期
dict_strategyperiod = {}

deleteButtonlist = []
comBox_setperiodlist = []

readstrategyinstrumentIDstaste = 1


# 用于动态加载策略
def dynamic_import(module):
    return importlib.import_module(module)


# 读取策略文件对应配置文件
def ReadStrategyInstrumentID(strategyname):
    global dict_strategyinstrument
    global readstrategyinstrumentIDstaste
    if readstrategyinstrumentIDstaste == 1:
        readstrategyinstrumentIDstaste = 0
        dict_tick = {}
        globalvar.dict_strategyinstrument[strategyname] = dict_tick
        with open('strategyfile\\' + strategyname + '.csv', 'r') as f:
            for line in f:
                print(strategyname + ' 策略对以下合约生效： ' + line)
                linelist = line.strip('\n').split(',')
                for k in iter(linelist):
                    globalvar.dict_strategyinstrument[strategyname][k] = k
                    print('读取策略' + strategyname + ' 交易合约：' + globalvar.dict_strategyinstrument[strategyname][line])

def PushToStrategy(strategyname, tickdata):
    keystate = False
    try:
        period=dict_strategyperiod[strategyname][str(tickdata.InstrumentID, encoding="utf8")]
        if dict_strategy[strategyname][str(tickdata.InstrumentID, encoding="utf8")] == 1 and period!= "":
            keystate = True
    except Exception as e:
        pass
    if keystate:
        # 读取策略文件对应生效的合约文件，与策略文件同名，后缀名是.csv
        # 暂时屏蔽 ReadStrategyInstrumentID(k)
        module = dynamic_import('strategyfile.' + strategyname)
        cal = module.MyStrategy('0', 0)
        print("Filterstrategyname:"+str(strategyname))

        filter2 = [[1, 1],
                   [1, 1],
                   [1, 1],
                   [1, 1],
                   [1, 1],
                   [1, 1]]
        cal.OnTick(tickdata, strategyname, filter2)
        print("module_strategy.PushToStrategy： %s %s" % (str(tickdata.InstrumentID, encoding="utf8"), k))


# 策略管理
def StrategyManager(tickdata):
    if globalvar.tradestate:
        # 定义跨模块全局变量
        global dict_strategy, dict_strategyrun
        # 多个策略分别计算
        try:
            for k in dict_strategy:
                PushToStrategy(k, tickdata)
        except Exception as e:
            print("module_strategy.StrategyManager Error:" + repr(e))


# 打开回测窗口
def Function_BackTest():
    button = globalvar.ui.MainWindow.sender()
    if button:
        row = globalvar.ui.table_strategy.indexAt(button.pos()).row()
    if globalvar.DialogSetInstrumentState:
        return
    globalvar.DialogSetInstrumentState = True
    globalvar.DialogBackTestPoint = globalvar.ui.DialogBackTest(globalvar.ui.table_strategy.item(row, 1).text())
    globalvar.DialogBackTestPoint.setWindowTitle(
        '量化回测参数设置（请随时关注回测模块更新http://www.vnpy.cn）：' + globalvar.ui.table_strategy.item(row, 1).text())
    globalvar.DialogBackTestPoint.show()
    screen = QDesktopWidget().screenGeometry()
    if screen.width() > 1600 and screen.height() > 900:
        screenRect = QApplication.desktop().screenGeometry()
        globalvar.DialogBackTestPoint.resize(max(1366, 0.70 * screenRect.width()), max(748, 0.70 * screenRect.height()))
        size = globalvar.DialogBackTestPoint.geometry()
        globalvar.DialogBackTestPoint.move((screen.width() - size.width()) / 2,
                                           (screen.height() - size.height()) / 2)
    else:
        globalvar.DialogBackTestPoint.showMaximized()
    QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling)
    globalvar.DialogBackTestPoint.exec_()


def Function_StrategyPosition():
    print("等待功能更新升级")


# 打开合约组选择窗口（设置策略的合约组，一共10个合约组）
def Function_SetInsIrumentID():
    button = globalvar.ui.MainWindow.sender()
    if button:
        row = globalvar.ui.table_strategy.indexAt(button.pos()).row()
    if globalvar.DialogSetInstrumentState:
        return
    globalvar.DialogSetInstrumentState = True
    dlg = globalvar.ui.DialogSetInstrumentID(globalvar.ui.table_strategy.item(row, 1).text())
    dlg.show()
    screenRect = QApplication.desktop().screenGeometry()
    dlg.resize(860, 0.46 * screenRect.height())
    # 居中窗口
    screen = QDesktopWidget().screenGeometry()
    size = dlg.geometry()
    dlg.move((screen.width() - size.width()) / 2,
             (screen.height() - size.height()) / 2)
    dlg.exec_()


def Function_EditStrategy(self):
    button = globalvar.ui.MainWindow.sender()
    if button:
        row = globalvar.ui.table_strategy.indexAt(button.pos()).row()
    os.system(globalvar.ui.table_strategy.item(row, 1).text())


# 主界面策略标签下过滤规则按钮下已设置规则数量
dict_ico_filternum = {0: 'ico/ico_selectnone.png',
                      1: 'ico/ico_1.png',
                      2: 'ico/ico_2.png',
                      3: 'ico/ico_3.png',
                      4: 'ico/ico_4.png',
                      5: 'ico/ico_5.png',
                      6: 'ico/ico_6.png'}

# 主界面策略标签下过滤规则按钮下已设置止损止盈图标
dict_ico_stopLosstakeprofit = {0: 'ico/ico_selectnone.png',
                               1: 'ico/ico_monitor1.png',
                               2: 'ico/ico_monitor2.png',
                               3: 'ico/ico_monitor3.png'}

# 主界面策略标签下周期conbox索引
dict_strategyperiod = {'M0': 0, 'M1': 1, 'M3': 2, 'M5': 3, 'M10': 4, 'M15': 5, 'M30': 6, 'M60': 7, 'M120': 8, 'D1': 9}


# 删除字符串多余的空格
def DeleteSpace(str):
    lastlengh = 0
    while (lastlengh != len(str)):
        str = str.replace(" ", "")
        lastlengh = len(str)
    return str


def SavePeriod(str):
    button = globalvar.ui.MainWindow.sender()
    if button:
        row = globalvar.ui.table_strategy.indexAt(button.pos()).row()
        period = comBox_setperiodlist[row].currentText()
        filename = globalvar.ui.table_strategy.item(row, 1).text().replace(".py", ".ini").replace(".pyc",
                                                                                                  ".ini").replace(
            ".pyd", ".ini")
        config = configparser.ConfigParser()
        config.read(filename, encoding="utf-8")
        config.set("setting", "period", period)
        config.write(open(filename, mode="w"))


# strategyfile目录下策略，添加到主视图table控件列表
def Function_ScanStrategy_SingleThreadPyManage():
    global dict_strategy
    global comBox_setperiod
    path = "strategyfile"
    ls = os.listdir(path)
    buttonid = 0
    for i in ls:
        c_path = os.path.join(path, i)
        if os.path.isdir(c_path):
            globalvar.ui.ClearPath(c_path,".txt")
        else:
            filename, type = os.path.splitext(c_path)
            if type == ".py" or type == ".pyd" or type == ".pyc":
                filename2 = filename.replace('strategyfile\\', '')
                if filename2 in dict_strategy:
                    # if dict_strategy[filename2] != globalvar.ui.fileTime(c_path):
                    # 修改了
                    pass
                else:
                    try:
                        filenameini = c_path.replace('py', 'ini')
                        #  实例化configParser对象
                        config = configparser.ConfigParser()
                        # -read读取ini文件
                        config.read(filenameini, encoding='utf-8')
                        if config.getint('setting', 'run') == 1:
                            dict_strategyrun[c_path] = 1
                        else:
                            dict_strategyrun[c_path] = 0
                        c_path2 = c_path.replace('strategyfile\\', '')

                        periodstr = DeleteSpace(config.get('setting', 'period'))
                        instrumentiddict = {}
                        groupfilelist0 = config.get('setting', 'groupfile')
                        groupfilelist = groupfilelist0.split(',')
                        print('len(groupfilelist): ' + str(len(groupfilelist)))
                        if len(groupfilelist) > 0 and groupfilelist0.replace(' ', '').replace(' ', '').replace(' ',
                                                                                                               '').replace(
                            ' ', '').replace(' ', '').replace(' ', '') != '':
                            for i in range(len(groupfilelist)):
                                print('groupfile2: ' + str(groupfilelist))
                                if groupfilelist != "":
                                    instrumentgroupfile = ("instrumentgroup/%s" % (groupfilelist[i]))
                                    with open(instrumentgroupfile, 'r') as f:
                                        for line in f:
                                            print(line)
                                            linelist = line.split(',')
                                            for f in linelist:
                                                instrumentiddict[f] = 1
                        dict_strategy[filename2] = instrumentiddict
                        for v in dict_strategy[filename2]:
                            print(str(v))
                        row_cnt = globalvar.ui.table_strategy.rowCount()  # 返回当前行数（尾部）
                        globalvar.ui.table_strategy.insertRow(row_cnt)  # 尾部插入一行新行表格
                        column_cnt = globalvar.ui.table_strategy.columnCount()  # 返回当前列数
                        # for column in range(column_cnt):
                        item = QTableWidgetItem(str(row_cnt + 1))
                        if dict_strategyrun[c_path] == 1:
                            item.setCheckState(QtCore.Qt.Checked)
                        else:
                            item.setCheckState(QtCore.Qt.Unchecked)
                        globalvar.ui.table_strategy.setItem(row_cnt, 0, item)
                        item = QTableWidgetItem(str(c_path))
                        globalvar.ui.table_strategy.setItem(row_cnt, 1, item)
                        globalvar.ui.table_strategy.setItem(row_cnt, 2, item)
                        globalvar.ui.table_strategy.setItem(row_cnt, 3, item)
                        deleteButton = QPushButton("选择合约组")
                        deleteButtonlist.append(deleteButton)
                        deleteButton.clicked.connect(Function_SetInsIrumentID)
                        buttonid = buttonid + 1
                        globalvar.ui.table_strategy.setCellWidget(row_cnt, 4, deleteButton)
                        deleteButton2 = QPushButton("用IDE编辑")
                        deleteButton2.setIcon(QtGui.QIcon('ico//ico_py.png'))
                        deleteButton2.clicked.connect(Function_EditStrategy)
                        globalvar.ui.table_strategy.setCellWidget(row_cnt, 5, deleteButton2)
                        deleteButton3 = QPushButton("回测")
                        deleteButton3.clicked.connect(Function_BackTest)
                        globalvar.ui.table_strategy.setCellWidget(row_cnt, 6, deleteButton3)
                        deleteButton4 = QPushButton("策略持仓")
                        deleteButton4.clicked.connect(Function_StrategyPosition)
                        globalvar.ui.table_strategy.setCellWidget(row_cnt, 7, deleteButton4)

                        comBox_setperiod = QtWidgets.QComboBox()
                        comBox_setperiodlist.append(comBox_setperiod)
                        comBox_setperiod.addItems(['由策略决定', 'M1', 'M3', 'M5', 'M10', 'M15', 'M30', 'M60', 'M120'])
                        comBox_setperiod.setCurrentIndex(dict_strategyperiod[periodstr])
                        comBox_setperiod.activated.connect(lambda: SavePeriod(comBox_setperiod.currentText()))
                        globalvar.ui.table_strategy.setCellWidget(row_cnt, 8, comBox_setperiod)
                    except Exception as e:
                        print("module_strategy.Function_ScanStrategy_SingleThreadPyManage Error:" + repr(e))

    try:
        print('strategy num:' + str(len(dict_strategy)))
        for k in dict_strategy:
            # print("(%s) %s" % (dict_strategy.index(k) + 1, k))
            print("key: %s, value:%s" % (k, str(dict_strategy[k])))
    except Exception as e:
        print("module_strategy.Function_ScanStrategy_SingleThreadPyManage2 Error:" + repr(e))


# 多进程模式，由C++回调调用Python策略,支持文件类型：（1）.py（2）.dll
def Function_scanstrategy_MulitProcess():
    path = "strategyfile"
    ls = os.listdir(path)
    for i in ls:
        c_path = os.path.join(path, i)
        if os.path.isdir(c_path):
            print(c_path)
            globalvar.ui.ClearPath(c_path)
        else:
            filename, type = os.path.splitext(c_path)
            if type == ".py" or type == ".pyd" or type == ".pyc":
                if c_path in dict_strategy:
                    if dict_strategy[c_path] != globalvar.ui.fileTime(c_path):
                        print("修改了")
                else:
                    try:
                        filenameini = c_path
                        filenameini = filenameini.replace('py', 'ini')
                        #  实例化configParser对象
                        config = configparser.ConfigParser()
                        config.read(filenameini, encoding='utf-8')
                        if config.getint('setting', 'run') == 1:
                            dict_strategyrun[c_path] = 1
                        else:
                            dict_strategyrun[c_path] = 0
                        dict_strategyopenrule[c_path] = config.get('setting', 'openrule')
                        dict_strategycloserule[c_path] = config.get('setting', 'closerule')
                        dict_strategy[c_path] = globalvar.ui.fileTime(c_path)
                        # print("find Strategy file:", c_path,globalvar.ui.fileTime(c_path))
                        row_cnt = globalvar.ui.table_strategy.rowCount()  # 返回当前行数（尾部）
                        # print("列数：",row_cnt)
                        globalvar.ui.table_strategy.insertRow(row_cnt)  # 尾部插入一行新行表格
                        column_cnt = globalvar.ui.table_strategy.columnCount()  # 返回当前列数
                        item = QTableWidgetItem(str(row_cnt + 1))
                        if dict_strategyrun[c_path] == 1:
                            item.setCheckState(QtCore.Qt.Checked)
                        else:
                            item.setCheckState(QtCore.Qt.Unchecked)
                        globalvar.ui.table_strategy.setItem(row_cnt, 0, item)
                        item = QTableWidgetItem(str("策略"))
                        globalvar.ui.table_strategy.setItem(row_cnt, 1, item)
                        item = QTableWidgetItem(str(c_path))
                        globalvar.ui.table_strategy.setItem(row_cnt, 2, item)
                        globalvar.ui.table_strategy.setItem(row_cnt, 3, item)
                        globalvar.ui.table_strategy.setItem(row_cnt, 4, item)
                        globalvar.ui.table_strategy.setItem(row_cnt, 5, item)

                    except:
                        pass

    try:
        for k in dict_strategy:
            # print("(%s) %s" % (dict_strategy.index(k) + 1, k))
            print("(%s) %s" % (dict_strategy[k] + 1, k))

    except Exception as e:
        print("module_strategy.Function_scanstrategy_MulitProcess Error:" + repr(e))


class MyStrategyMangement(object):
    # 多进程策略管理
    list_hwnd = []

    def StartStrategyProcess(self, msg):
        print("-->创建策略进程: ", msg[0], msg[1])
        sp = module_strategyprocess.StrategyProcess(msg[0])
        thidprocesshwnd = sp.GetProcessHwnd()
        print('进程句柄返回值： ' + str(thidprocesshwnd))
        self.list_hwnd.append(thidprocesshwnd)
        return ("完成创建策略进程: " + msg[0])

    def CreatStrategyProcess(self):
        # 进程池，用于策略计算，将回调函数注册给C++ DLL，形成多个进程实例，在多进程下运行策略计算
        pool = multiprocessing.Pool(4)
        result = []
        for i in range(4):
            msg = ['MA策略.py', i]
            result.append(pool.apply_async(self.StartStrategyProcess, (msg,)))

        # pool.close()
        # pool.join()
        for res in result:
            print("-->进程返回值：", res.get())

    def GetStrategyMode(self):
        try:
            # 实例化configParser对象
            config = configparser.ConfigParser()
            # read读取ini文件
            config.read('VNStrategyProcess.ini', encoding='utf-8')
            if config.getint('setting', 'mode') == 1:
                print("当前策略模式：单线程模式执行策略运算，仅支持.py策略文件")
            elif config.getint('setting', 'mode') == 2:
                print("当前策略模式：C++策略管理器，C++多进程模式执行策略运算，支持.py策略文件和.dll策略文件")
                self.CreatStrategyProcess()
        except Exception as e:
            print("module_strategy.GetStrategyMode Error:" + repr(e))


class RegSpOnStrategyCalculate(Thread):
    def __init__(self, name, sp):
        super().__init__()
        self.name = name
        self.sp = sp

    def run(self):
        self.sp.VNRegOnStrategyCalculate()
